/*
 * Copyright (c) 2015 Intel Corporation.
 *
 * Licensed under the Apache License, Version 2.0 (the "License");
 * you may not use this file except in compliance with the License.
 * You may obtain a copy of the License at
 *
 *     http://www.apache.org/licenses/LICENSE-2.0
 *
 * Unless required by applicable law or agreed to in writing, software
 * distributed under the License is distributed on an "AS IS" BASIS,
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 * See the License for the specific language governing permissions and
 * limitations under the License.
 */

#define _ASMLANGUAGE

#include <toolchain.h>
#include <sections.h>
#include <nano_private.h>
#include <arch/x86/asm.h>
#include <offsets.h>	/* nanokernel structure offset definitions */
#include <arch/cpu.h>	/* _NANO_ERR_SPURIOUS_INT */


GTEXT(_thread_entry_wrapper)
GTEXT(_thread_entry)
GTEXT(_irq_sw_handler)

/*
 * @brief Wrapper for _thread_entry
 *
 * The routine pops parameters for the _thread_entry from stack frame, prepared
 * by the _new_thread() routine.
 *
 * @return N/A
 */

SECTION_FUNC(TEXT, _thread_entry_wrapper)
	popl %eax
	popl %edx
	popl %ecx
	jmp _thread_entry


#if CONFIG_IRQ_OFFLOAD
SECTION_FUNC(TEXT, _irq_sw_handler)
	pushl %eax
	pushl %edx
	pushl %ecx
	movl $_irq_do_offload, %eax
	call _execute_handler
	pop %ecx
	pop %edx
	pop %eax
	iret
#endif

#if ALL_DYN_IRQ_STUBS > 0
BRANCH_LABEL(_DynIntStubCommon)
	pushl %eax
	pushl %ecx
	movl $_common_dynamic_irq_handler, %eax
	call _execute_handler
	/* Clean up and call IRET */
	pop %ecx
	pop %eax
	pop %edx
	iret


/* Create all the dynamic IRQ stubs
 *
 * NOTE: Please update DYN_STUB_SIZE in include/arch/x86/arch.h if you change
 * how large the generated stubs are, otherwise _get_dynamic_stub() will
 * be unable to correctly determine the offset
 */

/*
 * Create nice labels for all the stubs so we can see where we
 * are in a debugger
 */
.altmacro
.macro __INT_STUB_NUM id
BRANCH_LABEL(_DynIntStub\id)
.endm
.macro INT_STUB_NUM id
__INT_STUB_NUM %id
.endm
GTEXT(_DynIntStubsBegin)
SECTION_FUNC(TEXT, _DynIntStubsBegin)
stub_num = 0

.rept ((ALL_DYN_IRQ_STUBS + DYN_STUB_PER_BLOCK - 1) / DYN_STUB_PER_BLOCK)
	block_counter = 0
	.rept DYN_STUB_PER_BLOCK
		.if stub_num < ALL_DYN_IRQ_STUBS
			INT_STUB_NUM stub_num

			pushl %edx

			/*
			 * _common_dynamic_irq_handler() uses this to determine
			 * which ISR/param to use, see intconnect.c
			 */
			movl $stub_num, %edx

			/*
			 * Check to make sure this isn't the last stub in
			 * a block, in which case we just fall through
			 */
			.if (block_counter <> (DYN_STUB_PER_BLOCK - 1) && \
			     (stub_num <> ALL_DYN_IRQ_STUBS - 1))
				/* This should always be a 2-byte jmp rel8 */
				jmp 1f
			.endif
			stub_num = stub_num + 1
			block_counter = block_counter + 1
		.endif
	.endr
	/*
	 * This must a 5-bvte jump rel32, which is why _DynStubCommon
	 * is before the actual stubs
	 */
1:	jmp _DynIntStubCommon
.endr
#endif /* ALL_DYN_IRQ_STUBS */

